3.1.2 类型转换

2.原始类型

基本类型(基本数值、基本数据类型)是指非 对象 并且无方法的数据。

在 JavaScript 中,共有6种基本数据类型:string,number,boolean,null,undefined,symbol

3.值类型和引用类型

  • JavaScript中的变量类型有哪些?

    • (1)值类型:字符串(string)、数值(number)、布尔值(boolean)、none、undefined

    • (2)引用类型:对象(Object)、数组(Array)、函数(Function)

  • js中的值类型和引用类型的区别

    • 值类型:1、占用空间固定,保存在栈中
      • 2、保存与复制的是值本身
      • 3、使用typeof检测数据的类型
      • 4、基本类型数据是值类型
    • 引用类型:1、占用空间不固定,保存在堆中
      • 2、保存与复制的是指向对象的一个指针
      • 3、使用instanceof检测数据类型
      • 4、使用new()方法构造出的对象是引用型

4.隐式, 显式, 名义和鸭子类型

var a = 42;
var b = a + ""; // 隐式强制类型转换
var c = String( a ); // 显式强制类型转换

console.log(1+ + '2'+'2')   // 32
1
2
3
4
5
  • 隐式类型转换

    • 不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的
    • 比如,一个字符串可以和数字相加。
    • 如果字符串和数字相加,JavaScript会自动把数字转换成字符的,不管数字在前还是字符串在前
    • 1+null // 1
    • 1+undefined // NaN
    • 1+NaN // NaN
  • 显式解析数字字符串

    • 解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字。但解析和转换两者之间还是有明显的差别。
    • var a = "42";
    • var b = "42px";
    • Number( a ); // 42
    • parseInt( a ); // 42
    • Number( b ); // NaN
    • parseInt( b ); // 42
    • 解析允许字符串中含有非数字字符,解析按从做到右的顺序,如果遇到非数字字符就停止。而转换不允许出现非数字字符,否则会失败并返回NaN。
  • []+{} //"[object Object]"

  • {}+[] // 0

    • 这是两个复杂数据结构相加的例子,js的隐式类型转换
    • 原因是有的js解释器会将开头的 {} 看作一个代码块,而不是一个js对象,于是真正参与运算的是+[],就是将[]转换为number,于是得出答案0
    • 那么我们如何证明{}被看作一个代码块而不是一个js对象呢?很简单, 我们可以在{}里写上一些语句,比如: {console.log("hello")} + []
  • Number(undefined) // NaN

  • Number(null) // 0

  • Number(NaN) // NaN

  • Number(true) // 1

  • Number(false) // 0

  • ToString

    • 它负责处理非字符串到字符串的强制类型转换。
    • 基本类型值的字符串化规则为:null转换为“null”,undefined转换为“undefined”,true转换为“true”。
    • 数字的字符串化则遵循通用规则。不过那些极小和极大的数字使用指数形式:
    // 1.07 连续乘以七个 1000
    var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
    // 七个1000一共21位数字
    a.toString(); // "1.07e21"
    
    1
    2
    3
    4
  • JSON字符串化: JSON.stringify(..)并不是强制类型转换

JSON.stringify( 42 ); // "42"
JSON.stringify( "42" ); // ""42"" (含有双引号的字符串)
JSON.stringify( null ); // "null"
JSON.stringify( true ); // "true"

1
2
3
4
5
  • 所有安全的JSON值都可以使用JSON.stringify(..)字符串化。安全的JSON值是指你能够呈现为有效JSON格式的值。
  • JSON.stringify(..)在对象中遇到undefined、function和symbol时会自动将其忽略,在数组中则会返回null(以保证单元位置不变)。
JSON.stringify(undefined); // undefined
JSON.stringify(function () { }); // undefined
JSON.stringify(
    [1, undefined, function () { }, 4]
); // "[1,null,null,4]"
JSON.stringify(
    { a: 2, b: function () { } }
); // "{"a":2}"
1
2
3
4
5
6
7
8
  • 向JSON.stringify(..)传递一个可选参数replacer,它可以是数组或者函数,用来指定对象序列化过程中哪些属性应该被处理,哪些应该被排除。
    • 如果replacer是一个数组,那么它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称,除此之外其他的属性则被忽略。
    • 如果replacer是一个函数,它会对对象本身调用一次,然后对对象中的每个属性各调用一次,每次传递两个参数,键和值。如果要忽略某个键就返回undefined,否则返回指定的值。
var a = {
    b: 42,
    c: "42",
    d: [1, 2, 3]
};
JSON.stringify(a, ["b", "c"]); // "{"b":42,"c":"42"}"
JSON.stringify(a, function (k, v) {
    if (k !== "c") return v;
});
    // "{"b":42,"d":[1,2,3]}"
1
2
3
4
5
6
7
8
9
10
  • JSON.string还有一个可选参数space,用来指定输出的缩进格式。

    • space为正整数时是指定每一级缩进的字符数,它还可以是字符串,此时最前面的十个字符被用于每一级的缩进:
    var a = {
        b: 42,
        c: "42",
        d: [1, 2, 3]
    };
    JSON.stringify(a, null, 3);
    // "{
    // "b": 42,
    // "c": "42",
    // "d": [
    // 1,
    // 2,
    // 3
    // ]
    // }"
    JSON.stringify( a, null, "-----" );
    // "{
    // -----"b": 42,
    // -----"c": "42",
    // -----"d": [
    // ----------1,
    // ----------2,
    // ----------3
    // -----]
    // }"
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
  • 奇特的 ~ 运算符

  • indexOf(..)不仅能够得到子字符串的位置,还可以用来检查字符串中是否包含指定的子字符串,相当于一个条件判断。例如:

var a = "Hello World";
if (a.indexOf("lo") >= 0) { // true
    // 找到匹配!
}
if (a.indexOf("lo") != -1) { // true
    // 找到匹配!
}
if (a.indexOf("ol") < 0) { // true
    // 没有找到匹配!
}
if (a.indexOf("ol") == -1) { // true
    // 没有找到匹配!
}
1
2
3
4
5
6
7
8
9
10
11
12
13
  • = 0 和== -1这样的写法不是很好,称为“抽象渗漏”,意思是在代码中暴露了底层的实现细节,这里是指用-1作为失败时的返回值,这些细节应该被屏蔽掉。
    • 现在我们终于明白有什么用处了!和indexOf()一起可以将结果强制类型转换(实际上仅仅是转换)为真/假值:
var a = "Hello World";
~a.indexOf("lo"); // -4 <-- 真值!
if (~a.indexOf("lo")) { // true
    // 找到匹配!
}
~a.indexOf("ol"); // 0 <-- 假值!
!~a.indexOf("ol"); // true
if (!~a.indexOf("ol")) { // true
    // 没有找到匹配!
}
1
2
3
4
5
6
7
8
9
10

如果indexOf(..)返回-1,~将其转换为假值0,其他情况一律转换为真值。

  • 假值的相等比较
"0" == null; // false
"0" == undefined; // false
"0" == false; // true -- 晕!
"0" == NaN; // false
"0" == 0; // true
"0" == ""; // false
false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true -- 晕!
false == ""; // true -- 晕!
false == []; // true -- 晕!
false == {}; // false
"" == null; // false
"" == undefined; // false
"" == NaN; // false
"" == 0; // true -- 晕!
"" == []; // true -- 晕!
"" == {}; // false
0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true -- 晕!
0 == {}; // false
3、极端情况

[] == ![] // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


  • 编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言

    • 静态类型语言在编译时便已确定变量的类型,
    • 动态类型语言的变量类型要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型。
  • 鸭子类型指导我们只关注对象的行为,而不关注对象本身,

参考